home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / MoreFiles 1.4.3 / Sources / IterateDirectory.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  5.6 KB  |  187 lines  |  [TEXT/MPS ]

  1. /*
  2. **    IterateDirectory: File Manager directory iterator routines.
  3. **
  4. **    by Jim Luther
  5. **
  6. **    File:        IterateDirectory.c
  7. **
  8. **    Copyright © 1995-1996 Jim Luther
  9. **    All rights reserved.
  10. **
  11. **    You may incorporate this sample code into your applications without
  12. **    restriction, though the sample code has been provided "AS IS" and the
  13. **    responsibility for its operation is 100% yours.
  14. **
  15. **    IterateDirectory is designed to drop into the MoreFiles sample code
  16. **    library I wrote while in Apple Developer Technical Support
  17. */
  18.  
  19. #include <Types.h>
  20. #include <Errors.h>
  21. #include <Files.h>
  22.  
  23. #define    __COMPILINGMOREFILES
  24.  
  25. #include "MoreFilesExtras.h"
  26. #include "IterateDirectory.h"
  27.  
  28. /*
  29. **    Type definitions
  30. */
  31.  
  32. /* The IterateGlobals structure is used to minimize the amount of
  33. ** stack space used when recursively calling IterateDirectoryLevel
  34. ** and to hold global information that might be needed at any time.
  35. */
  36. #if PRAGMA_ALIGN_SUPPORTED
  37. #pragma options align=mac68k
  38. #endif
  39. struct IterateGlobals
  40. {
  41.     IterateFilterProcPtr    iterateFilter;    /* pointer to IterateFilterProc */
  42.     CInfoPBRec                cPB;            /* the parameter block used for PBGetCatInfo calls */
  43.     Str63                    itemName;        /* the name of the current item */
  44.     OSErr                    result;            /* temporary holder of results - saves 2 bytes of stack each level */
  45.     Boolean                    quitFlag;        /* set to true if filter wants to kill interation */
  46.     unsigned short            maxLevels;        /* Maximum levels to iterate through */
  47.     unsigned short            currentLevel;    /* The current level IterateLevel is on */
  48.     void                    *yourDataPtr;    /* A pointer to caller data the filter may need to access */
  49. };
  50. #if PRAGMA_ALIGN_SUPPORTED
  51. #pragma options align=reset
  52. #endif
  53.  
  54. typedef struct IterateGlobals IterateGlobals;
  55. typedef IterateGlobals *IterateGlobalsPtr;
  56.  
  57. /*****************************************************************************/
  58.  
  59. /*    Static Prototype */
  60.  
  61. static    void    IterateDirectoryLevel(long dirID,
  62.                                       IterateGlobalsPtr theGlobals);
  63.  
  64. /*****************************************************************************/
  65.  
  66. /*
  67. **    Functions
  68. */
  69.  
  70. static    void    IterateDirectoryLevel(long dirID,
  71.                                       IterateGlobalsPtr theGlobals)
  72. {
  73.     if ( (theGlobals->maxLevels == 0) ||                        /* if maxLevels is zero, we aren't checking levels */
  74.          (theGlobals->currentLevel < theGlobals->maxLevels) )    /* if currentLevel < maxLevels, look at this level */
  75.     {
  76.         short index = 1;
  77.         
  78.         ++theGlobals->currentLevel;    /* go to next level */
  79.         
  80.         do
  81.         {    /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
  82.         
  83.             /* Get next source item at the current directory level */
  84.             
  85.             theGlobals->cPB.dirInfo.ioFDirIndex = index;
  86.             theGlobals->cPB.dirInfo.ioDrDirID = dirID;
  87.             theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);        
  88.     
  89.             if ( theGlobals->result == noErr )
  90.             {
  91.                 /* Call the IterateFilterProc */
  92.                 CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
  93.                 
  94.                 /* Is it a directory? */
  95.                 if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  96.                 {
  97.                     /* We have a directory */
  98.                     if ( !theGlobals->quitFlag )
  99.                     {
  100.                         /* Dive again if the IterateFilterProc didn't say "quit" */
  101.                         IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
  102.                     }
  103.                 }
  104.             }
  105.             
  106.             ++index; /* prepare to get next item */
  107.         } while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
  108.         
  109.         if ( theGlobals->result == fnfErr )    /* fnfErr is OK - it only means we hit the end of this level */
  110.             theGlobals->result = noErr;
  111.             
  112.         --theGlobals->currentLevel;    /* return to previous level as we leave */
  113.     }
  114. }
  115.  
  116. /*****************************************************************************/
  117.  
  118. pascal    OSErr    IterateDirectory(short vRefNum,
  119.                                  long dirID,
  120.                                  StringPtr name,
  121.                                  unsigned short maxLevels,
  122.                                  IterateFilterProcPtr iterateFilter,
  123.                                  void *yourDataPtr)
  124. {
  125.     IterateGlobals    theGlobals;
  126.     OSErr            result;
  127.     long            theDirID;
  128.     short            theVRefNum;
  129.     Boolean            isDirectory;
  130.     
  131.     /* Make sure there is a IterateFilter */
  132.     if ( iterateFilter != NULL )
  133.     {
  134.         /* Get the real directory ID and make sure it is a directory */
  135.         result = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
  136.         if ( result == noErr )
  137.         {
  138.             if ( isDirectory == true )
  139.             {
  140.                 /* Get the real vRefNum */
  141.                 result = DetermineVRefNum(name, vRefNum, &theVRefNum);
  142.                 if ( result == noErr )
  143.                 {
  144.                     /* Set up the globals we need to access from the recursive routine. */
  145.                     theGlobals.iterateFilter = iterateFilter;
  146.                     theGlobals.cPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
  147.                     theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
  148.                     theGlobals.itemName[0] = 0;
  149.                     theGlobals.result = noErr;
  150.                     theGlobals.quitFlag = false;
  151.                     theGlobals.maxLevels = maxLevels;
  152.                     theGlobals.currentLevel = 0;    /* start at level 0 */
  153.                     theGlobals.yourDataPtr = yourDataPtr;
  154.                 
  155.                     /* Here we go into recursion land... */
  156.                     IterateDirectoryLevel(theDirID, &theGlobals);
  157.                     
  158.                     result = theGlobals.result;    /* set the result */
  159.                 }
  160.             }
  161.             else
  162.             {
  163.                 result = dirNFErr;    /* a file was passed instead of a directory */
  164.             }
  165.         }
  166.     }
  167.     else
  168.     {
  169.         result = paramErr;    /* iterateFilter was NULL */
  170.     }
  171.     
  172.     return ( result );
  173. }
  174.  
  175. /*****************************************************************************/
  176.  
  177. pascal    OSErr    FSpIterateDirectory(const FSSpec *spec,
  178.                                     unsigned short maxLevels,
  179.                                     IterateFilterProcPtr iterateFilter,
  180.                                     void *yourDataPtr)
  181. {
  182.     return ( IterateDirectory(spec->vRefNum, spec->parID, (StringPtr)spec->name,
  183.                         maxLevels, iterateFilter, yourDataPtr) );
  184. }
  185.  
  186. /*****************************************************************************/
  187.